package com.huayun.plugin.bdfAnalysis.controller;

import org.springframework.stereotype.Service;

import java.util.*;
import java.util.List;

@Service
public class BDFAnalysisService {


    public static class FaceInfo {
        private Integer id;
        private List<Double> data;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public List<Double> getData() {
            return data;
        }

        public void setData(List<Double> data) {
            this.data = data;
        }
    }
    public static class IntersectFacesParam {
        private List<List<Double>> linesInfo;
        private List<FaceInfo> facesInfo;

        public IntersectFacesParam(List<List<Double>> linesInfo, List<FaceInfo> facesInfo) {
            this.linesInfo = linesInfo;
            this.facesInfo = facesInfo;
        }

        public IntersectFacesParam() {
        }

        public List<List<Double>> getLinesInfo() {
            return linesInfo;
        }

        public void setLinesInfo(List<List<Double>> linesInfo) {
            this.linesInfo = linesInfo;
        }

        public List<BDFAnalysisService.FaceInfo> getFacesInfo() {
            return this.facesInfo;
        }

        public void setFacesInfo(List<FaceInfo> facesInfo) {
            this.facesInfo = facesInfo;
        }
    }

    // 三维向量类（简化实现）
    public static class Vec3 {
        public double x, y, z;

        public Vec3(double x, double y, double z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        public Vec3 subtract(Vec3 other) {
            return new Vec3(x - other.x, y - other.y, z - other.z);
        }

        public Vec3 cross(Vec3 other) {
            return new Vec3(
                    y * other.z - z * other.y,
                    z * other.x - x * other.z,
                    x * other.y - y * other.x
            );
        }

        public Vec3 scale(double s) {
            return new Vec3(x * s, y * s, z * s);
        }

        public double dot(Vec3 other) {
            return x * other.x + y * other.y + z * other.z;
        }

        public double lengthSquared() {
            return x * x + y * y + z * z;
        }
    }

    List<List<Integer>> calculateIntersectFaces(List<List<Double>> linesInfo, List<BDFAnalysisService.FaceInfo> facesInfo){
        //面片包围盒
        Map<Integer,List<Double>> mapFaceToBox = new HashMap<>();
        Map<Integer, List<Double>> facesMap = new HashMap<>();


        //遍历获取包围盒
        for (BDFAnalysisService.FaceInfo faceInfo : facesInfo) {
            List<Double> box = calculateFaceBox(faceInfo.getData());
            facesMap.put(faceInfo.getId(), faceInfo.getData());
            mapFaceToBox.put(faceInfo.getId(), box);
        }


        List<List<Integer>> ListListIntersectID = new ArrayList<>();
        //相交计算，先进行包围盒筛选，再进行点计算
        for(int lineIndex = 0;lineIndex < linesInfo.size();lineIndex++){
            //线段的点
            List<Double> linePoint1 = Arrays.asList(linesInfo.get(lineIndex).get(0),linesInfo.get(lineIndex).get(1),linesInfo.get(lineIndex).get(2));
            List<Double> linePoint2 = Arrays.asList(linesInfo.get(lineIndex).get(3),linesInfo.get(lineIndex).get(4),linesInfo.get(lineIndex).get(5));

            //1.通过Box获取有相交的面，效率高
            List<Integer> listBoxIntersecID = new ArrayList<>();
            mapFaceToBox.forEach((id,box) -> {
                Boolean intersect = judgeLineFaceIntersectBoxPoints(linePoint1,linePoint2,box);
                if(intersect){
                    listBoxIntersecID.add(id);
                }
            });

            List<Integer> listIntersecID = new ArrayList<>();
            //2.对于相交的面，再通过三角面片的点进行计算
            for(int nBoxInterIndex = 0;nBoxInterIndex < listBoxIntersecID.size();nBoxInterIndex++){
                Integer faceID = listBoxIntersecID.get(nBoxInterIndex);
                List<Double> listTrianglePoints = facesMap.get(faceID);
                //判断是否是9的倍数
                if(listTrianglePoints.size()%9 != 0){
                    continue;
                }

                Boolean intersect = judgeLineFaceIntersectTrianglesPoints(linePoint1,linePoint2,listTrianglePoints);
                if(intersect){
                    listIntersecID.add(faceID);
                }
            }

            ListListIntersectID.add(listIntersecID);
        }
        return ListListIntersectID;
    }

    //判断线段是否与包围盒相交
    private boolean judgeLineFaceIntersectBoxPoints(List<Double> p1, List<Double> p2, List<Double> box) {
        List<Double> boxMin = Arrays.asList(box.get(0),box.get(1),box.get(2));
        List<Double> boxMax = Arrays.asList(box.get(3),box.get(4),box.get(5));

        // 对x轴进行检查
        if (!checkAxis(p1.get(0),p2.get(0),boxMin.get(0),boxMax.get(0))) {
            return false;
        }

        // 对y轴进行检查
        if (!checkAxis(p1.get(1),p2.get(1),boxMin.get(1),boxMax.get(1))) {
            return false;
        }

        // 对z轴进行检查
        if (!checkAxis(p1.get(2),p2.get(2),boxMin.get(2),boxMax.get(2))) {
            return false;
        }
        return true;
    }
    //计算某个轴向是否投影相交
    private boolean checkAxis(double p1,double p2,double bMin,double bMax) {
        //如果p1 p2的最小值小于b1,b2的最小值，或者如果p1 p2的最大值大于b1,b2的最大值，此时无交点
        double pMin = p1 < p2 ? p1 : p2;
        double pMax = p1 > p2 ? p1 : p2;
        if(pMax < bMin || pMin > bMax){
            return false;
        }
        return true;
    }
    //计算face的Box
    List<Double> calculateFaceBox(List<Double> listPoint){
        double dMin = 999999;
        double dMax = -999999;
        List<Double> listMin = Arrays.asList(dMin,dMin,dMin);
        List<Double> listMax = Arrays.asList(dMax,dMax,dMax);

        for(int n = 0;n < listPoint.size() / 3;n++){
            List<Double> listCoord = new ArrayList<>();
            listCoord.add(listPoint.get(n * 3 + 0));
            listCoord.add(listPoint.get(n * 3 + 1));
            listCoord.add(listPoint.get(n * 3 + 2));
            for(int m = 0;m < 3;m++){
                if(listCoord.get(m) < listMin.get(m)){
                    listMin.set(m,listCoord.get(m));
                }
                if(listCoord.get(m) > listMax.get(m)){
                    listMax.set(m,listCoord.get(m));
                }
            }
        }
        List<Double> box = new ArrayList<>();
        box.addAll(listMin);
        box.addAll(listMax);
        return box;
    }
    Boolean judgeLineFaceIntersectTrianglesPoints(List<Double> p1,List<Double> p2,List<Double> facePoints){
        Boolean bIntesect = false;
        for(int nTriangleIndex = 0;nTriangleIndex < facePoints.size() / 9;nTriangleIndex++){
            List<Double> trianglePoints = new ArrayList<>();
            for(int n = 0;n < 9;n++){
                trianglePoints.add(facePoints.get(nTriangleIndex * 9 + n));
            }

            //计算与单个面片是否相交
            bIntesect = judgeLineFaceIntersectTrianglePoints(p1,p2,trianglePoints);
            if(bIntesect){
                //相交即跳出
                break;
            }
        }
        return  bIntesect;
    }
    //通过三角面片确定线段是否与face相交
    Boolean judgeLineFaceIntersectTrianglePoints(List<Double> p1,List<Double> p2,List<Double> facePoints){
        Vec3 linePoint1 = new Vec3(p1.get(0),p1.get(1),p1.get(2));
        Vec3 linePoint2 = new Vec3(p2.get(0),p2.get(1),p2.get(2));

        Vec3 facePoint1 = new Vec3(facePoints.get(0),facePoints.get(1),facePoints.get(2));
        Vec3 facePoint2 = new Vec3(facePoints.get(3),facePoints.get(4),facePoints.get(5));
        Vec3 facePoint3 = new Vec3(facePoints.get(6),facePoints.get(7),facePoints.get(8));

        return intersects(linePoint1,linePoint2,facePoint1,facePoint2,facePoint3);
    }
    // 判断线段是否与三角形相交
    public static boolean intersects(Vec3 p0, Vec3 p1, Vec3 v0, Vec3 v1, Vec3 v2) {
        Vec3 edge1 = v1.subtract(v0);
        Vec3 edge2 = v2.subtract(v0);
        Vec3 h = p1.subtract(p0).cross(edge2);
        double a = edge1.dot(h);

        // 如果 a 是 0，说明射线与三角形平行
        if (Math.abs(a) < 1e-8) return false;

        double f = 1.0 / a;
        Vec3 s = p0.subtract(v0);
        double u = f * s.dot(h);

        // u 超出三角形范围
        if (u < 0.0 || u > 1.0) return false;

        Vec3 q = s.cross(edge1);
        double v = f * p1.subtract(p0).dot(q);

        // v 超出三角形范围
        if (v < 0.0 || u + v > 1.0) return false;

        // t 是线段参数：p0 + t * (p1 - p0)
        double t = f * edge2.dot(q);

        // 线段相交要求 t 在 [0, 1] 范围内
        return t >= 0.0 && t <= 1.0;
    }
}
